﻿/**

 * Copyright (c) 2015-2016, FastDev 刘强 (fastdev@163.com) & Quincy.

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

using MsgPack.Serialization;
using OF.Cache2.Entity;
using StackExchange.Redis;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using OF.Cache2.Core;
using OF.Cache2.Redis;
using OF.Cache2.Impl;

namespace OF.Cache2.Test
{
    public class TestCacheDict
    {
        public static void Test()
        {
            DateTime dtNow = DateTime.Now;
            FIFODict<TestCacheItem> fifoDict = new FIFODict<TestCacheItem>(3);
            var item1 = new TestCacheItem("1") { Value = "123" };
            var item2 = new TestCacheItem("2") { Value = "234" };
            var item3 = new TestCacheItem("3") { Value = "345" };
            item1.SetExpireDate(dtNow.Add(TimeSpan.FromSeconds(1)));
            item2.SetExpireDate(dtNow.Add(TimeSpan.FromSeconds(1)));
            item3.SetExpireDate(dtNow.Add(TimeSpan.FromSeconds(1)));
            fifoDict.SetValue(item1);
            fifoDict.SetValue(item2);
            fifoDict.SetValue(item3);
            TestCacheItem temp = null;
            Console.WriteLine("get 1:" + fifoDict.TryGetValue("1", out temp));
            Console.WriteLine("get 2:" + fifoDict.TryGetValue("2", out temp));
            Console.WriteLine("get 3:" + fifoDict.TryGetValue("3", out temp));

            Console.WriteLine("get 1:" + fifoDict.TryGetValue("1", out temp));
            var item4 = new TestCacheItem("4") { Value = "456" };
            item4.SetExpireDate(dtNow.Add(TimeSpan.FromSeconds(1)));
            fifoDict.SetValue(item4);
            Console.WriteLine("get 1:" + fifoDict.TryGetValue("1", out temp));
            Console.WriteLine("get 2:" + fifoDict.TryGetValue("2", out temp));
            Console.WriteLine("get 3:" + fifoDict.TryGetValue("3", out temp));
            Console.WriteLine("get 4:" + fifoDict.TryGetValue("4", out temp));
            fifoDict.Remove("4");
            Console.WriteLine("get 4:" + fifoDict.TryGetValue("4", out temp));
            Thread.Sleep(2000);
            item1.SetExpireDate(DateTime.Now.Add(TimeSpan.FromSeconds(1)));
            fifoDict.SetValue(item1); 
            Console.WriteLine("get 1:" + fifoDict.TryGetValue("1", out temp));
            Console.WriteLine("get 2:" + fifoDict.TryGetValue("2", out temp));
            item2.SetExpireDate(DateTime.Now.Add(TimeSpan.FromSeconds(1)));
            fifoDict.SetValue(item2);
            Console.WriteLine("get 2:" + fifoDict.TryGetValue("2", out temp));
            Console.WriteLine("get 3:" + fifoDict.TryGetValue("3", out temp));
            Console.WriteLine("get 4:" + fifoDict.TryGetValue("4", out temp));

            Console.ReadLine();
        }
    }

    public class TestCacheItem : ICacheItem
    {
        public string key
        { get; set; }

        public DateTime expireDate
        { get; set; }


        public TestCacheItem()
        { 
        
        }

        public DateTime GetExpireDate()
        {
            return expireDate;
        }

        public void SetExpireDate(DateTime expireDate)
        {
            this.expireDate = expireDate;
        }

        public string GetKey()
        {
            return this.key;
        }

        public string Value
        { get; set; }

        public DateTime CreateDate
        { get; set; }

        public TestCacheItem(string key)
        {
            this.key = key;
            CreateDate = DateTime.Now;
        }
    }


    public class TestRedis
    {
        private static void TestGetData()
        {
            if (RedisHelper.IsConnectionOk())
            {
                try
                {
                    Thread.Sleep(2000);
                    Console.WriteLine("data is:" + (string)RedisHelper.Manager.GetDatabase(1).StringGet("1"));
                }
                catch (StackExchange.Redis.RedisConnectionException ex)
                {
                    Console.WriteLine("not connectioned!");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
            else
            {
                Console.WriteLine("not connectioned!");
            }
        }

        public static void TestExpire()
        {
            var man = RedisHelper.Manager;
            if (RedisHelper.IsConnectionOk())
            {
                RedisHelper.Manager.GetDatabase(1).StringSet("1", "123", TimeSpan.FromSeconds(6));
            }

            for (int i1 = 0; i1 < 5; i1++)
            {
                TestGetData();
            }
        }

        public static void TestMoveLink()
        {
            for (int count = 1; count <= 5; count++)
            {
                Console.WriteLine("count is:" + count);
                for (int i1 = 0; i1 < count; i1++)
                {
                    HeadTailLink<string> stringLink = new HeadTailLink<string>();
                    LinkItem<string> selItem = null;
                    Console.WriteLine("move " + (i1 + 1) + " at first");
                    for (int j1 = 0; j1 < count; j1++)
                    {
                        var data = new LinkItem<string> { Data = (j1 + 1).ToString() };
                        if (i1 == j1)
                        {
                            selItem = data;
                        }
                        stringLink.Add(data);
                    }
                    stringLink.MoveItemHead(selItem);
                    DumpTwoWay(stringLink);
                    Console.WriteLine();
                }
            }
        }

        public static void TestDeleteLink()
        {
            HeadTailLink<string> stringLink = new HeadTailLink<string>();
            stringLink.Add(new LinkItem<string> { Data = "1" });
            stringLink.Add(new LinkItem<string> { Data = "2" });
            stringLink.Add(new LinkItem<string> { Data = "3" });
            stringLink.Add(new LinkItem<string> { Data = "4" });
            DumpTwoWay(stringLink);
            for (int i1 = 0; i1 < 5; i1++)
            {
                stringLink.RemoveTail();
                DumpTwoWay(stringLink);
            }
        }

        public static void TestAddLink()
        {
            HeadTailLink<string> stringLink = new HeadTailLink<string>();
            stringLink.Add(new LinkItem<string> { Data = "1" });
            stringLink.Add(new LinkItem<string> { Data = "2" });
            stringLink.Add(new LinkItem<string> { Data = "3" });
            stringLink.Add(new LinkItem<string> { Data = "4" });
            DumpTwoWay(stringLink);
        }

        private static void DumpTwoWay(HeadTailLink<string> link)
        {
            List<string> strList = new List<string>();
            var currentNode = link.head;
            while (currentNode != null)
            {
                strList.Add(currentNode.Data);
                currentNode = currentNode.next;
            }
            Console.WriteLine("asc " + string.Join(" ", strList));
            strList.Clear();
            currentNode = link.tail;
            while (currentNode != null)
            {
                strList.Add(currentNode.Data);
                currentNode = currentNode.prev;
            }
            Console.WriteLine("desc " + string.Join(" ", strList));
        }

        public static void TestLock()
        {
            DateTime dtStart = DateTime.Now;
            object obj = new object();
            for (int i1 = 0; i1 < 10000; i1++)
            {
                lock (obj)
                { 
                    
                }
            }
            Console.WriteLine("10000 elapse:" + DateTime.Now.Subtract(dtStart).TotalMilliseconds);
            Console.ReadLine();
        }
        public static void TestConnectionOnClose()
        {
            var man = RedisHelper.Manager;
            if (RedisHelper.IsConnectionOk())
            {
                RedisHelper.Manager.GetDatabase(1).StringSet("1", "123", TimeSpan.FromSeconds(360));
            }
            while (true)
            {
                for (int i1 = 0; i1 < 5; i1++)
                {
                    TestGetData();
                }
                Console.WriteLine("re connection test!");
                Console.ReadLine();
            }
        }

        private static void TraceValue(string name, TestCacheItem item)
        {
            string value = null;
            if (item != null)
            {
                value = item.Value;
            }
            Console.WriteLine(name + ",Value is:" + value);
            Console.WriteLine();
        }

        public static void TestWritePerformance()
        {
            DateTime dtStart = DateTime.Now;
            int i2 = 1;
            Func<TestCacheItem> func1 = () =>
            {
                return new TestCacheItem("1")
                {
                    Value = "Item " + (i2++)
                };
            };
            BusinessLayer2Cache<TestCacheItem> cache1 = new BusinessLayer2Cache<TestCacheItem>(100, 0, 1, "bu", 60);
            Parallel.For(0, 10000, new ParallelOptions { MaxDegreeOfParallelism = 10 }, (i1) =>
            {
                cache1.GetItem(i1.ToString(), func1);
            });
            Console.WriteLine("elapse:" + DateTime.Now.Subtract(dtStart).TotalMilliseconds);
            Parallel.For(0, 10000, new ParallelOptions { MaxDegreeOfParallelism = 10 }, (i1) =>
            {
                cache1.Remove(i1.ToString());
            });
            Console.ReadLine();
        }

        public static void Test2Layer()
        {
            BusinessLayer2Cache<TestCacheItem> cache1 = new BusinessLayer2Cache<TestCacheItem>(100, 0, 1, "bu", 60);
            cache1.MockId = "C1";


            int i1 = 1;
            Func<TestCacheItem> func1 = () =>
            {
                return new TestCacheItem("1")
                {
                    Value = "Item " + (i1++)
                };
            };

            int i4 = 4;
            Func<TestCacheItem> func4 = () =>
            {
                return new TestCacheItem("4")
                {
                    Value = "Item " + (i4++)
                };
            };

            TraceValue("1", cache1.GetItem("1", func1));
            TraceValue("2", cache1.GetItem("1", func1));
            cache1.SetValue("1", new TestCacheItem("1")
            {
                Value = "Item 2"
            });
            Thread.Sleep(100);
            TraceValue("3", cache1.GetItem("1", func1));
            TraceValue("4", cache1.GetItem("4", func4));
            cache1.Remove("4");
            Thread.Sleep(100);
            TraceValue("5", cache1.GetItem("4", func4));
            BusinessLayer2Cache<TestCacheItem> cache2 = new BusinessLayer2Cache<TestCacheItem>(100, 1, 1, "bu", 60);
            cache2.MockId = "C2";
            TraceValue("6", cache2.GetItem("1", func1));
            TraceValue("7", cache2.GetItem("1", func1));
            cache2.SetValue("1", new TestCacheItem("1")
            {
                Value = "Item 3"
            });
            Thread.Sleep(100);
            TraceValue("8", cache1.GetItem("1", func1));
            TraceValue("9", cache2.GetItem("1", func1));

            TraceValue("8", cache1.GetItem("1", func1));

            TraceValue("10", cache1.GetItem("4", func4));
            TraceValue("11", cache2.GetItem("4", func4));
            cache1.Remove("4");
            Thread.Sleep(100);
            TraceValue("12", cache1.GetItem("4", func4));
            TraceValue("13", cache2.GetItem("4", func4));

            cache1.Remove("4");
            cache1.Remove("1");
            RedisHelper.DoDispose();
            Console.ReadLine();
        }

        public static string To16String(byte[] btArray)
        {
            if (btArray == null)
            {
                return null;
            }
            StringBuilder sb = new StringBuilder(btArray.Length * 2);
            foreach (byte bt in btArray)
            {
                sb.Append(Convert.ToString(bt, 16));
            }
            return sb.ToString();
        }

        public static void TestStringBytes()
        {
            string key = RedisHelper.MergeKey("k1", "k2", "k3");
            byte[] data = null;

            byte[] keyDataBytes = RedisHelper.CombineKeyData(key, data);
            Tuple<string, byte[]> keyData = RedisHelper.SplitKeyData(keyDataBytes);

            Console.WriteLine("str:" + keyData.Item1 + ",bt3:" + To16String(keyData.Item2));
            Console.ReadLine();
        }

        public static void TestBytes()
        {
            RedisBusinessHelper rd = new RedisBusinessHelper(0, 0, "b1");
            RedisBusinessHelper rd2 = new RedisBusinessHelper(0, 1, "b1");
            Console.WriteLine("set 11:" + rd.SetBytes("k1", new byte[] { 1, 1 }));
            Console.WriteLine("set 12:" + rd.SetBytes("k2", new byte[] { 1, 2 }));
            Console.WriteLine("set 21:" + rd2.SetBytes("k1", new byte[] { 2, 1 }));
            Console.WriteLine("set 22:" + rd2.SetBytes("k2", new byte[] { 2, 2 }));

            Console.WriteLine("Get 11:" + To16String(rd.GetBytes("k1")));
            Console.WriteLine("Get 12:" + To16String(rd.GetBytes("k2")));
            Console.WriteLine("Get 21:" + To16String(rd2.GetBytes("k1")));
            Console.WriteLine("Get 22:" + To16String(rd2.GetBytes("k2")));

            Console.WriteLine("Has 11:" + rd.HasKey("k1"));
            Console.WriteLine("Has 12:" + rd.HasKey("k2"));
            Console.WriteLine("Has 21:" + rd2.HasKey("k1"));
            Console.WriteLine("Has 22:" + rd2.HasKey("k2"));

            Console.WriteLine("Remove 11:" + rd.Remove("k1"));
            Console.WriteLine("Remove 12:" + rd.Remove("k2"));
            Console.WriteLine("Remove 21:" + rd2.Remove("k1"));
            Console.WriteLine("Remove 22:" + rd2.Remove("k2"));

            Console.WriteLine("Get 2 11:" + To16String(rd.GetBytes("k1")));
            Console.WriteLine("Get 2 12:" + To16String(rd.GetBytes("k2")));
            Console.WriteLine("Get 2 21:" + To16String(rd2.GetBytes("k1")));
            Console.WriteLine("Get 2 22:" + To16String(rd2.GetBytes("k2")));
            Console.WriteLine("Get 2 22:" + (rd2.GetValue("k2") == RedisValue.Null));
            Console.ReadLine();
        }
    }
}
